# -*- coding: utf-8 -*-
import base64
import requests
import json
from urllib.parse import urljoin, unquote_plus, quote, urlencode
from urllib.parse import urlsplit
from werkzeug import urls
from odoo.http import request
from odoo import api, SUPERUSER_ID, _
from odoo import models, fields
from odoo.exceptions import UserError
import logging
from ast import literal_eval

_logger = logging.getLogger(__name__)

AMPERSAND = "&"
QUESTIONMARK = "?"

WECOM_SERVER_APIS = {
    "CODE_TO_SESSION_KEY": {"path": "/cgi-bin/miniprogram/jscode2session", "method": "GET"},
    "GET_ACCESS_TOKEN": {"path": "/cgi-bin/gettoken", "method": "GET"},
    "GET_API_DOMAIN_IP": {"path": "/cgi-bin/get_api_domain_ip", "method": "GET"},
    "USER_CREATE": {"path": "/cgi-bin/user/create", "method": "POST"},
    "USER_GET": {"path": "/cgi-bin/user/get", "method": "GET"},
    "USER_UPDATE": {"path": "/cgi-bin/user/update", "method": "POST"},
    "USER_DELETE": {"path": "/cgi-bin/user/delete", "method": "GET"},
    "USER_BATCH_DELETE": {"path": "/cgi-bin/user/batchdelete", "method": "POST"},
    "USER_SIMPLE_LIST": {"path": "/cgi-bin/user/simplelist", "method": "GET"},
    "USER_LIST": {"path": "/cgi-bin/user/list", "method": "GET"},
    "USERID_TO_OPENID": {"path": "/cgi-bin/user/convert_to_openid", "method": "POST"},
    "OPENID_TO_USERID": {"path": "/cgi-bin/user/convert_to_userid", "method": "POST"},
    "USER_AUTH_SUCCESS": {"path": "/cgi-bin/user/authsucc", "method": "GET"},
    "DEPARTMENT_CREATE": {"path": "/cgi-bin/department/create", "method": "POST"},
    "DEPARTMENT_UPDATE": {"path": "/cgi-bin/department/update", "method": "POST"},
    "DEPARTMENT_DELETE": {"path": "/cgi-bin/department/delete", "method": "GET"},
    "DEPARTMENT_LIST": {"path": "/cgi-bin/department/list", "method": "GET"},
    "TAG_CREATE": {"path": "/cgi-bin/tag/create", "method": "POST"},
    "TAG_UPDATE": {"path": "/cgi-bin/tag/update", "method": "POST"},
    "TAG_DELETE": {"path": "/cgi-bin/tag/delete", "method": "GET"},
    "TAG_GET_USER": {"path": "/cgi-bin/tag/get", "method": "GET"},
    "TAG_ADD_USER": {"path": "/cgi-bin/tag/addtagusers", "method": "POST"},
    "TAG_DELETE_USER": {"path": "/cgi-bin/tag/deltagusers", "method": "POST"},
    "TAG_GET_LIST": {"path": "/cgi-bin/tag/list", "method": "GET"},
    "BATCH_JOB_GET_RESULT": {"path": "/cgi-bin/batch/getresult", "method": "GET"},
    "BATCH_INVITE": {"path": "/cgi-bin/batch/invite", "method": "POST"},
    "AGENT_GET": {"path": "/cgi-bin/agent/get", "method": "GET"},
    "AGENT_SET": {"path": "/cgi-bin/agent/set", "method": "POST"},
    "AGENT_GET_LIST": {"path": "/cgi-bin/agent/list", "method": "GET"},
    "MENU_CREATE": {"path": "/cgi-bin/menu/create", "method": "POST"},
    "MENU_GET": {"path": "/cgi-bin/menu/get", "method": "GET"},
    "MENU_DELETE": {"path": "/cgi-bin/menu/delete", "method": "GET"},
    "MESSAGE_SEND": {"path": "/cgi-bin/message/send", "method": "POST"},
    "MESSAGE_REVOKE": {"path": "/cgi-bin/message/revoke", "method": "POST"},
    "GET_STATISTICS": {"path": "/cgi-bin/message/get_statistics", "method": "POST"},
    "MEDIA_GET": {"path": "/cgi-bin/media/get", "method": "GET"},
    "MEDIA_UPLOAD": {"path": "/cgi-bin/media/upload", "method": "POST"},
    "MEDIA_UPLOADIMG": {"path": "/cgi-bin/media/uploadimg", "method": "POST"},
    "GET_USER_INFO": {"path": "/cgi-bin/user/getuserinfo", "method": "GET"},
    "GET_USER_DETAIL": {"path": "/cgi-bin/user/getuserdetail", "method": "POST"},
    "GET_TICKET": {"path": "/cgi-bin/ticket/get", "method": "GET"},
    "GET_JSAPI_TICKET": {"path": "/cgi-bin/get_jsapi_ticket", "method": "GET"},
    "GET_CORP_CHECKIN_OPTION": {"path": "/cgi-bin/checkin/getcorpcheckinoption", "method": "POST"},
    "GET_CHECKIN_OPTION": {"path": "/cgi-bin/checkin/getcheckinoption", "method": "POST"},
    "GET_CHECKIN_DATA": {"path": "/cgi-bin/checkin/getcheckindata", "method": "POST"},
    "GET_APPROVAL_DATA": {"path": "/cgi-bin/corp/getapprovaldata", "method": "POST"},
    "GET_INVOICE_INFO": {"path": "/cgi-bin/card/invoice/reimburse/getinvoiceinfo", "method": "POST"},
    "GET_JOIN_QRCODE": {"path": "/cgi-bin/corp/get_join_qrcode", "method": "GET"},
    "UPDATE_INVOICE_STATUS": {"path": "/cgi-bin/card/invoice/reimburse/updateinvoicestatus", "method": "POST"},
    "BATCH_UPDATE_INVOICE_STATUS": {"path": "/cgi-bin/card/invoice/reimburse/updatestatusbatch", "method": "POST"},
    "BATCH_GET_INVOICE_INFO": {"path": "/cgi-bin/card/invoice/reimburse/getinvoiceinfobatch", "method": "POST"},
    "APP_CHAT_CREATE": {"path": "/cgi-bin/appchat/create", "method": "POST"},
    "APP_CHAT_GET": {"path": "/cgi-bin/appchat/get", "method": "GET"},
    "APP_CHAT_UPDATE": {"path": "/cgi-bin/appchat/update", "method": "POST"},
    "APP_CHAT_SEND": {"path": "/cgi-bin/appchat/send", "method": "POST"}
}


class WecomCorp(models.Model):
    _name = "wecom.corp"
    _description = "WeCom Corp"

    name = fields.Char(required=True, index=True)
    corpid = fields.Char("Corp ID")

    _sql_constraints = [
        ("name_uniq", "unique (name)", "Name exist."),
        ("corpid_uniq", "unique (corpid)", "Corp ID exist."),
    ]


class WecomApp(models.Model):
    _name = "wecom.app"
    _order = "sequence, id"
    _description = "WeCom APP"

    sequence = fields.Integer(default=10)
    name = fields.Char(required=True, index=True)
    corp_id = fields.Many2one("wecom.corp", string="Corp", required=True, ondelete="restrict")
    corpid = fields.Char(related="corp_id.corpid")
    appid = fields.Char()
    agentid = fields.Char(string="Agentid", required=True, copy=False)
    secret = fields.Char(string="Secret", required=True, copy=False)
    access_token = fields.Char("Access Token", readonly=True)
    enable_oauth = fields.Boolean(string="OAuth")
    oauth_url = fields.Char(compute='_compute_oauth_url')

    _sql_constraints = [
        ("name_uniq", "unique (corp_id, name)", "Name exist.")
    ]

    @api.depends('corp_id.corpid', 'agentid')
    def _compute_oauth_url(self):
        for app in self:
            if isinstance(app.id, int):
                app.oauth_url = app.get_oauth_uri()
            else:
                app.oauth_url = ''

    @api.model
    def get_default_app(self):
        return self.sudo().search([], limit=1)

    # 向微信发送请求
    def _post(self, path, args=None, **kwargs):
        access_token = self.get_access_token()
        endpoint = self._get_full_path(path) + "?access_token=" + access_token
        response = requests.post(endpoint, args, **kwargs).json()
        if self._is_token_expired(response.get('errcode')):
            access_token = self.refresh_access_token()
            endpoint = self._get_full_path(path) + "?access_token=" + access_token
            response = requests.post(endpoint, args, **kwargs).json()
        return response

    # 向微信发送请求
    def _get(self, path, args=None):
        access_token = self.get_access_token()
        if not access_token:
            raise UserError('连接企微失败，请检查企微key!')
        endpoint = self._get_full_path(path) + "?access_token=" + access_token
        response = requests.get(endpoint, params=args).json()
        if self._is_token_expired(response.get('errcode')):
            access_token = self.refresh_access_token()
            response = requests.get(self._get_full_path(path) + "?access_token=" + access_token, params=args).json()
        return response

    # 获取access token
    def get_access_token(self):
        if not self.access_token:
            return self.refresh_access_token()
        return self.access_token

    # 获取access token
    def refresh_access_token(self):
        server_api = WECOM_SERVER_APIS["GET_ACCESS_TOKEN"]
        _logger.info("request access token, corpid: %s, secret: %s", (self.corpid, self.secret))
        res = requests.get(self._get_full_path(server_api.get('path')), {"corpid": self.corpid, "corpsecret": self.secret}).json()
        if not res["errcode"]:
            self.sudo().access_token = res['access_token']
            return self.access_token
        else:
            raise Exception(f"获取腾讯 access token 失败 {res['errmsg']}")

    def get_oauth_uri(self, redirect=''):
        self.ensure_one()

        # fixme 以下这个版本有空再调试一下
        # endpoint = "https://open.weixin.qq.com/connect/oauth2/authorize"
        # wechat_redirect_uri = urljoin(self.get_base_url(), '/wecom_oauth/authorize')
        # response_type = 'code'
        # scope = 'snsapi_base'
        # state = {'db': request.session.db, 'wecom_app_id': self.id, 'redirect': redirect}
        # params = {
        #     'appid': self.corpid,
        #     'redirect_uri': wechat_redirect_uri,
        #     'response_type': response_type,
        #     'scope': scope,
        #     'state': state,
        # }
        # return f'{endpoint}?{urlencode(params)}'

        return f"https://open.weixin.qq.com/connect/oauth2/authorize?" \
               f"appid={self.corpid}" \
               f"&redirect_uri={urljoin(self.get_base_url(), '/wecom_oauth/authorize')}" \
               f"&response_type=code&scope=snsapi_base" \
               f"&state={base64.standard_b64encode(json.dumps({'db': request.session.db, 'wecom_app_id': self.id, 'redirect': redirect}).encode()).decode()}" \
               f"&agentid={self.agentid}" \
               f"#wechat_redirect"

    def get_user_info(self, code):
        # https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE
        return self._get(WECOM_SERVER_APIS["GET_USER_INFO"].get('path'), {"code": code})

    # 读取通讯录成员
    def get_user(self, userid):
        return self._get(WECOM_SERVER_APIS["USER_GET"].get('path'), {"userid": userid})
        # "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s"

    def media_upload(self, message=None, **kwargs):
        return self._post(WECOM_SERVER_APIS["MEDIA_UPLOAD"].get('path'), message, **kwargs)

    # /cgi-bin/message/send
    def message_send(self, message):
        return self._post(WECOM_SERVER_APIS["MESSAGE_SEND"].get('path'), message)

    # /cgi-bin/department/list
    def get_department_list(self):
        return self._get(WECOM_SERVER_APIS['DEPARTMENT_LIST'].get('path'))

    # /cgi-bin/user/list
    def get_user_list(self, message):
        return self._get(WECOM_SERVER_APIS['USER_LIST'].get('path'), message)

    # /cgi-bin/user/create
    def user_create(self, message):
        return self._post(WECOM_SERVER_APIS['USER_CREATE'].get('path'), message)

    def user_delete(self, message):
        return self._get(WECOM_SERVER_APIS['USER_DELETE'].get('path'), message)

    # code 2 sessionjs_code=%s&grant_type=authorization_code
    def code2Session(self, code):
        server_api = WECOM_SERVER_APIS["CODE_TO_SESSION_KEY"]
        return self._get(server_api.get('path'), {"js_code": code, "grant_type": "authorization_code"})

    def openid_to_userid(self, message):
        return self._post(WECOM_SERVER_APIS["OPENID_TO_USERID"].get('path'), json=message)

    @staticmethod
    def _get_full_path(path):
        base = "https://qyapi.weixin.qq.com"
        return base + path if path[0] == "/" else base + "/" + path

    @staticmethod
    def _is_token_expired(errCode):
        if errCode in (40014, 42001, 42007, 42009):
            return True
        return False

